package com.lifp.service;

import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baidu.aip.util.Base64Util;
import com.lifp.config.BaiDuAiRestFaceConfig;
import com.lifp.constant.FaceConsts;
import com.lifp.dto.BaiDuFaceImageRegisterDTO;
import com.lifp.entity.BaiDuFaceUser;
import com.lifp.enums.ImageTypeEnum;
import com.lifp.utils.FaceTokenUtil;
import com.lifp.vo.Result;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Description REST接口 方式，人脸库接口
 * @Author lifp
 * @Date 2023/2/26
 * @Version 1.0
 */
@Service
public class BaiDuAiRestFaceLibraryService {
    @Autowired
    private FaceTokenUtil tokenUtil;
    @Autowired
    private BaiDuAiRestFaceConfig faceConfig;


    /**
    * 人脸注册接口
    */
    public Result registerFace(BaiDuFaceImageRegisterDTO imageRegisterDTO) {

        String requestUrl = FaceConsts.USER_ADD+"?access_token=" + tokenUtil.getToken();

        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("group_id", faceConfig.getDefaultFaceGroupId());
        paramMap.put("image", imageRegisterDTO.getImage());
        paramMap.put("image_type", ImageTypeEnum.BASE64.getCode());
        paramMap.put("user_id", imageRegisterDTO.getUser_id());
        /**
         * 操作方式
         * APPEND: 当user_id在库中已经存在时，对此user_id重复注册时，新注册的图片默认会追加到该user_id下
         * REPLACE : 当对此user_id重复注册时,则会用新图替换库中该user_id下所有图片
         * 默认使用APPEND
         */
        paramMap.put("action_type", "APPEND");


        String response = HttpRequest.post(requestUrl)
                .header(Header.CONTENT_TYPE, "application/json")
                .form(paramMap)//表单内容
                .timeout(20000)//超时，毫秒
                .execute().body();

        JSONObject object = JSONUtil.parseObj(response);

        if(object != null && "SUCCESS".equals(object.get("error_msg"))){
            return Result.ok(imageRegisterDTO.getUser_id(),"注册成功");
        }
        return Result.error(object.get("error_msg"));
    }

    /**
     * 人脸更新接口
     */
    public Result updateUser(BaiDuFaceImageRegisterDTO imageRegisterDTO) {
        String requestUrl = FaceConsts.USER_UPDATE+"?access_token=" + tokenUtil.getToken();

        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("group_id", faceConfig.getDefaultFaceGroupId());
        paramMap.put("image", imageRegisterDTO.getImage());
        paramMap.put("image_type", ImageTypeEnum.BASE64.getCode());
        paramMap.put("user_id", imageRegisterDTO.getUser_id());
        /**
         * 操作方式
         * UPDATE: 会使用新图替换库中该user_id下所有图片, 若user_id不存在则会报错
         * REPLACE : 当user_id不存在时, 则会注册这个user_id的用户
         * 默认使用UPDATE
         */
        paramMap.put("action_type", "UPDATE");


        String response = HttpRequest.post(requestUrl)
                .header(Header.CONTENT_TYPE, "application/json")
                .form(paramMap)//表单内容
                .timeout(20000)//超时，毫秒
                .execute().body();

        JSONObject object = JSONUtil.parseObj(response);

        if(object != null && "SUCCESS".equals(object.get("error_msg"))){
            return Result.ok(imageRegisterDTO.getUser_id(),"更新成功");
        }
        return Result.error(object.get("error_msg"));
    }


    public Result loginByFaceImg64(String image64) {
        BaiDuFaceUser baiDuFaceUser = search(image64);

        if(baiDuFaceUser != null){
            //todo 结合user_id,进行数据库比对，下发token，完成登录
            String user_id = baiDuFaceUser.getUser_id();

            return Result.ok(user_id,"登录成功！");
        }
        return Result.error("认证失败，请重试!");
    }

    @SneakyThrows
    public Result loginByFaceImgFile(MultipartFile imgFile) {
        //图片文件转BASE64
        String img64 = Base64Util.encode(imgFile.getBytes());

        BaiDuFaceUser baiDuFaceUser = search(img64);

        if(baiDuFaceUser != null){
            //todo 结合user_id,进行数据库比对，下发token，完成登录
            String user_id = baiDuFaceUser.getUser_id();

            return Result.ok(user_id,"登录成功！");
        }
        return Result.error("认证失败，请重试!");
    }

    /**
     * 人脸搜索 1:N 识别
     */
    public BaiDuFaceUser search(String imgBase64){
        //todo 进行活体检测


        String requestUrl = FaceConsts.SEARCH+"?access_token=" + tokenUtil.getToken();

        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("image", imgBase64);
        paramMap.put("group_id_list", faceConfig.getDefaultFaceGroupId());
        paramMap.put("image_type", ImageTypeEnum.BASE64.getCode());

        String response = HttpRequest.post(requestUrl)
                .header(Header.CONTENT_TYPE, "application/json")
                .form(paramMap)//表单内容
                .timeout(20000)//超时，毫秒
                .execute().body();

        JSONObject object = JSONUtil.parseObj(response);

        if(!object.isNull("error_msg") && "SUCCESS".equals(object.get("error_msg"))){

            //拿到识别到的集合
            JSONArray jsonArray = new JSONArray((((JSONObject) object.get("result")).get("user_list")).toString());
            List<BaiDuFaceUser> baiDuFaceUsers = JSONUtil.toList(jsonArray, BaiDuFaceUser.class);

            if(baiDuFaceUsers == null || baiDuFaceUsers.size()<1){
                return null;
            }

            //筛选
            List<BaiDuFaceUser> resultList = baiDuFaceUsers.stream()
                    .filter(item->{
                        //筛选出80分以上的
                        return item.getScore().compareTo(BigDecimal.valueOf(80)) >0;
                    })
                    .sorted((x, y) -> {
                        //根据score 由高到低排序
                        return y.getScore().compareTo(x.getScore());
                    }).collect(Collectors.toList());

            return resultList.get(0);
        }

        return null;
    }
}
